package foundation.web.flow;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.zkoss.lang.Strings;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zul.Column;
import org.zkoss.zul.FieldComparator;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.api.Columns;
import org.zkoss.zul.api.Paging;
import org.zkoss.zul.event.PagingEvent;

import foundation.common.util.BusinessException;
import foundation.common.util.CommonGeneralUtil;
import foundation.common.util.FinderFilter;
import foundation.common.util.OrderFilter;
import foundation.common.util.OrderType;
import foundation.common.util.PagedFinder;
import foundation.zk.crud.composer.AbstractCRUDManagerComposer;
import ar.com.sne.bean.BaseBO;
import ar.com.sne.util.ListUtil;



/**
 * @author hernan
 */
/**
 * This class implements the abstract behaviour of paging on DB
 * 
 * 
 */
@SuppressWarnings("unchecked")
public abstract class AbstractPagingComposer extends
		AbstractCRUDManagerComposer {
	
	private final Log log = LogFactory.getLog(getClass());

	public Paging paging;	
	public OrderFilter order;

	
	//private int previouPageSize=0;
	
	private List<OrderFilter> orderByList = new ArrayList<OrderFilter>();
	
	
	public Map<String,Object> addExtraFilters= new HashMap<String, Object>();
	public List<OrderFilter> addExtraOrders= new ArrayList<OrderFilter>();
	

	public List<OrderFilter> getAddExtraOrders() {
		return addExtraOrders;
	}


	public void setAddExtraOrders(List<OrderFilter> addExtraOrders) {
		this.addExtraOrders = addExtraOrders;
	}


	@Override
	public void doAfterCompose(Component comp) throws Exception {	
		super.doAfterCompose(comp);	
		paging.setPageSize(12);
		paging.addEventListener("onPaging", new EventListener() {
			public void onEvent(Event event) {
				onPagingEvent(event);
			}
		});
		
		if(this.getGrdSearchResult()!=null){
			Columns cols= this.getGrdSearchResult().getColumnsApi();
			for(Object objCol: cols.getChildren()){
				org.zkoss.zul.api.Column col = (org.zkoss.zul.api.Column)objCol;		
				col.addEventListener("onSort", new EventListener() {
					public void onEvent(Event event) {
						//para que on llame al evento onSort propio de la grilla
						event.stopPropagation();
						orderByList= new ArrayList<OrderFilter>();
						onSortEvent(event);						 
					}
				});
			}
		}
		
				
	}
	
	
	protected void onSortEvent(Event event) {	
		
		int PAGE_SIZE = paging.getPageSize();
		Comparator cmpr;
		Event pe = (Event) event;
		Column c = (Column) event.getTarget();		

		String orderBy;
		 String  sortDirection = c.getSortDirection();
		  
		 if ("ascending".equals(sortDirection)) {
				cmpr = c.getSortDescending();
				if (cmpr instanceof FieldComparator) {
					orderBy = ((FieldComparator) cmpr).getOrderBy();	
					//
					StringTokenizer st = new StringTokenizer(orderBy,",");
					for (int i = 0; i <= st.countTokens(); i++) {
						orderBy = st.nextToken();
						//
						orderBy = CommonGeneralUtil
						.substringBefore(orderBy, "DESC").trim();
				order = new OrderFilter();
				order.setOrder(orderBy);
				order.setOrderType(OrderType.Descending);
				orderByList.add(order);
				//
					} 
					
				}				
			}
		 
		 else if (("descending".equals(sortDirection))
					|| ("natural".equals(sortDirection))
					|| (Strings.isBlank(sortDirection))) {
				cmpr = c.getSortAscending();
				if (cmpr instanceof FieldComparator) {
					orderBy = ((FieldComparator) cmpr).getOrderBy();
					StringTokenizer st = new StringTokenizer(orderBy,",");
					for (int i = 0; i <= st.countTokens(); i++) {
						orderBy = st.nextToken();
					orderBy = CommonGeneralUtil.substringBefore(orderBy, "ASC")
							.trim();
					order = new OrderFilter();
					order.setOrder(orderBy);
					order.setOrderType(OrderType.Ascending);
					orderByList.add(order);
					}
				}
			}	
		 
		 this.clearOrderColum();	
		c.setSortDirection("ascending".equals(sortDirection)?"descending":"ascending");
		paging.setActivePage(0);		
		this.searchPagingComposer( 0, paging.getPageSize());
	}
	
	protected void onPagingEvent(Event event) {
		int PAGE_SIZE = paging.getPageSize();
		PagingEvent pe = (PagingEvent) event;		
		int pgno = pe.getActivePage();		
		int ofs = pgno * PAGE_SIZE;
		// Redraw current paging		
		searchPagingComposer(ofs, PAGE_SIZE);
	}
	
	
	public void refrescarPagina(){
		int PAGE_SIZE = paging.getPageSize();						
		int pgno = paging.getActivePage();				
		int ofs = pgno * PAGE_SIZE;
		// Redraw current paging		
		searchPagingComposer(ofs, PAGE_SIZE);
	}
	public void searchPagingComposer(int firstResult, int maxResults) throws BusinessException {		
		log.debug("first result: "+firstResult+", max: "+maxResults);
			paging.setPageSize(12);

			FinderFilter filter = this.setterFilters();
		if(!ListUtil.isNullOrEmpty(this.orderByList)){
			filter.getOrders().clear();
			filter.addAllOrder(this.orderByList);	
		}		
		if(this.getAddExtraFilters().size()>0){
			for(String key: this.getAddExtraFilters().keySet()){
				filter.addFilter(key, this.getAddExtraFilters().get(key));
			}
		}
		if(this.getAddExtraOrders().size()>0){
			filter.addAllOrder(this.getAddExtraOrders());			
		}
		PagedFinder pf = new PagedFinder();
		pf.setFilter(filter);
		pf.setFirstResult(firstResult);
		pf.setMaxResult(maxResults);		
	
		this.setObjectReturnList(searchPaging(pf).getResultList());
		
		ListModelList modelo =null;
		if(this.getGrdSearchResult()!=null){
			modelo = (ListModelList) this.getGrdSearchResult().getModel();	
		}
		
		paging.setTotalSize(pf.getCount());
		
		if (modelo != null) {	
			modelo.clear();
			modelo.addAll(this.getObjectReturnList());
		}
		this.setLabelNotResult();
	}
	

	
	@Override
	public void callMethods() {
		if(order!=null){
			orderByList.add(order);
		}
		log.debug("search button clicked");	
		int pgno = paging.getActivePage();		
		int ofs = pgno * paging.getPageSize();
		searchPagingComposer(ofs, paging.getPageSize());
	}
	
	@Override
	public void onClick$searchButton() {
		log.debug("search button clicked");
		paging.setActivePage(0);	
		this.order=null;
		if(this.orderByList==null){
			this.orderByList= new ArrayList<OrderFilter>();
		}
		this.searchPagingComposer(0, paging.getPageSize());
	}
	
		
	/**
	 * Clear Filters button click handler
	 */
	@Override
	public void onClick$clearFiltersButton(Event event) {
		super.onClick$clearFiltersButton(event);
		this.clearLabelNotResult();		
		paging.setActivePage(0);		
		paging.setTotalSize(1);		
		orderByList= new ArrayList<OrderFilter>();
		this.clearOrderColum();
		
	}	
	
	
	private void clearOrderColum(){
		//pongo en blanco los ordenamientos
		if(this.getGrdSearchResult()!=null){
			Columns cols= this.getGrdSearchResult().getColumnsApi();
			for(Object objCol: cols.getChildren()){
				org.zkoss.zul.api.Column col = (org.zkoss.zul.api.Column)objCol;
				col.setSortDirection("natural");	
			}				
		}
	}

	/**
	 * Definition of filters 
	 * 
	 * @return the object filter with all filters setted
	 */
	protected abstract  FinderFilter setterFilters();
	

	
	
	/**
	 * 
	 * 
	 * @param pagedFinder
	 * @return
	 */
	protected abstract  PagedFinder searchPaging(PagedFinder pf);

	
	
	
	@SuppressWarnings("unchecked")
	@Override
	protected List search() {			
		return null;
	}
	
	
	@Override
	protected void clearFilterCriteriaFields() {
	
	}

	@Override
	protected void deleteObject(BaseBO objectToDelete) {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected String getEditPageName() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	protected String getObjectDescription(BaseBO objectToDelete) {
		// TODO Auto-generated method stub
		return null;
	}


	public Map<String, Object> getAddExtraFilters() {
		return addExtraFilters;
	}


	public void setAddExtraFilters(Map<String, Object> addExtraFilters) {
		this.addExtraFilters = addExtraFilters;
	}


	@Override
	public BaseBO getNewObjectPersistentObjectToAdd(){	
		return null;	
	}	
	
}
